package segmentation;

import java.util.Collections;
import java.util.Vector;

import preproc.Image;
import textPixelId.ClusterInfo;
import utils.Constants;

public class Segmenter {
	public static int num_chars = Constants.NUM_CHARS_EVAL;
	
	public void segmentation(Image img) {
		/*
		 * TODO (for the last milestone): split large clusters (e.g. vertical segmentation)
		 * possible implementation:
		 * keep only clusters which have size larger than 0.1 * max_cluster_size
		 * split the largest cluster until the required number of chars 
		 * (or an alternative condition - e.g. equilibrated clusters) is met  
		 */
		
		
		// the clusters are sorted by the number of pixels
//		if (img.clusters.size() == 0) return;
//		
//		// get largest cluster
//		ClusterInfo largest = null;
//		int maxSize = 0;
//		
//		for (ClusterInfo c: img.clusters) {
//			if ((largest==null) || ((c.r1-c.r0) * (c.c1-c.c0) > maxSize))  {
//				largest = c;
//				maxSize = (c.r1-c.r0) * (c.c1-c.c0);
//			}
//		}
		
		
		if (Constants.USE_SEGMENTATION) {
			Vector<ClusterInfo> clusters = img.clusters;
			while (clusters.size() < num_chars) {
				// try to split large clusters
				
				ClusterInfo largest = clusters.get(0);
				int num;
				int idxC = -1;
				double valMin = 0;
				
				for (int c=largest.c0+1; c<=largest.c1-1; c++) {
					num = 0;
					for (int r=largest.r0; r<=largest.r1; r++) {
						num += (img.clustered[r][c]==largest.cluster_idx) ? 1:0;
					}
					
					double val = 0;
					val = num;

					
					if (Constants.USE_GAUSSIAN_PRIOR) {
						double mean = ((double)largest.c0 + largest.c1)/2;
						double deviation = 1.0 * (largest.c1 - largest.c0);
						val *= Math.exp( (c-mean)*(c - mean) / (2*deviation) );
					}
					
					if ( (idxC==-1) || (val<valMin) ) {
						idxC = c;
						valMin = val;
					}
				}
				// split by the idxC column
	
				int newClusterIdx = img.maxClusterIdx++;
				
				// r0 and r1 are reversed, they will be updated while checking pixels
				ClusterInfo newCluster = new ClusterInfo(largest.r1, idxC, largest.r0, largest.c1, newClusterIdx, 0);
				
				
				for (int r=largest.r0; r<=largest.r1; r++) {
					for (int c=idxC; c<=largest.c1; c++) {
						if (img.clustered[r][c] == largest.cluster_idx) {
							largest.num_pixels--;
							img.clustered[r][c] = newClusterIdx;
							newCluster.num_pixels++;
							if (r < newCluster.r0) newCluster.r0 = r;
							if (r > newCluster.r1) newCluster.r1 = r;
						}
					}
				}
				
				// update r0, r1 for the old cluster
				largest.c1 = idxC-1;
				outer_for:
				for (int r=largest.r0; r<=largest.r1; r++) {
					for (int c=largest.c0; c<idxC;c++) {
						if (img.clustered[r][c]==largest.cluster_idx) {
							largest.r0 = r;
							break outer_for;
						}
					}
				}
				outer_for:
				for (int r=largest.r1; r>=largest.r0; r--) {
					for (int c=largest.c0; c<idxC;c++) {
						if (img.clustered[r][c]==largest.cluster_idx) {
							largest.r1 = r;
							break outer_for;
						}
					}
				}
				
				
				clusters.add(newCluster);
				Collections.sort(clusters);
			}
		}	
		
		for (int i=0; i<num_chars; i++) {
			if (img.clusters.size() == i) {
				break;
			}
			ClusterInfo cluster = img.clusters.get(i);
			CharInfo charInfo = new CharInfo(cluster);
			for (int r=cluster.r0; r<=cluster.r1; r++) {
				for (int c=cluster.c0; c<=cluster.c1; c++) {
					if (img.clustered[r][c] == cluster.cluster_idx) {
						charInfo.charImage[r-cluster.r0][c-cluster.c0] = 0;		// black
					}
					else {
						charInfo.charImage[r-cluster.r0][c-cluster.c0] = 255; 	// white
					}
				}
			}
			img.chars.add(charInfo);
		}
		Collections.sort(img.chars);
		
		if (Constants.DEBUG) {
			img.showImageWithBoxes();
		}
		
	}
}
